package com.song.article.controller;


import com.mongodb.client.gridfs.GridFSBucket;
import com.song.api.BaseController;
import com.song.api.config.MyServiceList;
import com.song.api.config.RabbitMQConfig;
import com.song.api.controller.article.ArticleControllerApi;
import com.song.api.controller.article.ArticlePortalControllerApi;
import com.song.article.service.ArticleService;
import com.song.enums.ArticleCoverType;
import com.song.enums.ArticleReviewStatus;
import com.song.enums.YesOrNo;
import com.song.grace.result.GraceJSONResult;
import com.song.grace.result.ResponseStatusEnum;
import com.song.pojo.Category;
import com.song.pojo.bo.NewArticleBO;
import com.song.pojo.vo.ArticleDetailVO;
import com.song.utils.JsonUtils;
import com.song.utils.PagedGridResult;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class ArticleController extends BaseController implements ArticleControllerApi {

    private static final Logger LOG = LoggerFactory.getLogger(ArticleController.class);

    @Value("${freemarker.html.article}")
    private String articlePath;

    @Autowired
    private ArticleService articleService;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 注入服务发现，可以获得已注册的服务相关信息
    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private ArticlePortalControllerApi articlePortalControllerApi;

    @Override
    public GraceJSONResult createArticle(@Valid NewArticleBO newArticleBO) {

        // 判断文章封面图类型，单图必填，纯文字设置为空，考虑后续扩展用 else if
        if (newArticleBO.getArticleType().equals(ArticleCoverType.ONE_IMAGE.type)) {
            if (StringUtils.isBlank(newArticleBO.getArticleCover())) {
                return GraceJSONResult.errorCustom(ResponseStatusEnum.ARTICLE_COVER_NOT_EXIST_ERROR);
            }
        } else if (newArticleBO.getArticleType().equals(ArticleCoverType.WORDS.type)) {
            newArticleBO.setArticleCover("");
        }

        // 判断分类id是否存在
        String allCategoryJson = redis.get(REDIS_ALL_CATEGORY);
        Category category = null;
        if (StringUtils.isBlank(allCategoryJson)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_OPERATION_ERROR);
        } else {
            List<Category> categoryList = JsonUtils.jsonToList(allCategoryJson, Category.class);
            // 判断文章分类(领域)是否为空
            category = queryCategoryIsExist(categoryList, newArticleBO.getCategoryId());
            if (category == null) {
                return GraceJSONResult.errorCustom(ResponseStatusEnum.ARTICLE_CATEGORY_NOT_EXIST_ERROR);
            }
        }
        // 测试输出
//        System.out.println(newArticleBO.toString());
        articleService.createArticle(newArticleBO, category);

        return GraceJSONResult.ok();
    }

    @Override
    public GraceJSONResult queryMyList(String userId,
                                       String keyword,
                                       Integer status,
                                       Date startDate,
                                       Date endDate,
                                       Integer page,
                                       Integer pageSize) {

        // 0.判断userId不能为空
        if (StringUtils.isBlank(userId)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.ARTICLE_QUERY_PARAMS_ERROR);
        }

        if (page == null) {
            page = COMMON_START_PAGE;
        }

        if (pageSize == null) {
            pageSize = COMMON_PAGE_SIZE;
        }

        PagedGridResult pagedGridResult = articleService.queryMyArticleList(userId, keyword, status, startDate, endDate, page, pageSize);

        return GraceJSONResult.ok(pagedGridResult);
    }

    @Override
    public GraceJSONResult queryAllList(Integer status, Integer page, Integer pageSize) {
        if (page == null) {
            page = COMMON_START_PAGE;
        }

        if (pageSize == null) {
            pageSize = COMMON_PAGE_SIZE;
        }

        PagedGridResult pagedGridResult = articleService.queryAllArticleList(status, page, pageSize);

        return GraceJSONResult.ok(pagedGridResult);
    }

    @Override
    public GraceJSONResult doReview(String articleId, Integer passOrNot) {

        if (articleId == null) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.ARTICLE_REVIEW_ERROR);
        }

        Integer pendingStatus;
        if (passOrNot.equals(YesOrNo.YES.type)) {
            //审核通过
            pendingStatus = ArticleReviewStatus.SUCCESS.type;
        } else if (passOrNot.equals(YesOrNo.NO.type)) {
            //审核失败
            pendingStatus = ArticleReviewStatus.FAILED.type;
        } else {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.ARTICLE_REVIEW_ERROR);
        }

        // 保存到数据库，更改文章的状态为审核成功或失败
        articleService.updateArticleStatus(articleId, pendingStatus);

        if (pendingStatus.equals(ArticleReviewStatus.SUCCESS.type)) {
            // 审核成功，生成html
            try {
                // 文章生成HTML存储到GridFS中,放回GridFSId
                String articleMongoId = createArticleHTMLToGridFS(articleId);
                // GridFSId存储到文章信息中
                articleService.updateArticleToGridFS(articleId, articleMongoId);
                // 发起消息到MQ队列，让消费者监听并执行下载html
                doDownloadArticleHTMLByMQ(articleId,articleMongoId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return GraceJSONResult.ok();
    }

    @Override
    public GraceJSONResult delete(String userId, String articleId) {
        articleService.deleteArticle(userId, articleId);
        return GraceJSONResult.ok();
    }

    @Override
    public GraceJSONResult withdraw(String userId, String articleId) {
        articleService.withdrawArticle(userId, articleId);
        return GraceJSONResult.ok();
    }

    /**
     * 发起RabbitMQ下载文章HTML消息
     *
     * @param articleId
     * @param articleMongoId
     */
    private void doDownloadArticleHTMLByMQ(String articleId, String articleMongoId) {
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.EXCHANGE_ARTICLE,
                "article.download.do",
                articleId + "," + articleMongoId);
    }


    /**
     * 文章生成HTML
     *
     * @param articleId
     * @throws Exception
     */
    public void createArticleHTML(String articleId) throws Exception {
        // 0.配置freemarker基本环境
        Configuration cfg = new Configuration(Configuration.getVersion());
        // 声明freemarker模板所需加载的目录的位置
        String classpath = this.getClass().getResource("/").getPath();
        cfg.setDirectoryForTemplateLoading(new File(classpath + "templates"));

        // 1.获得现有的模板ftl文件
        Template template = cfg.getTemplate("detail.ftl", "utf-8");

        // 2.获得动态数据
        ArticleDetailVO articleVO = getArticleDetail(articleId);

        Map<String, Object> map = new HashMap<>();
        map.put("articleDetail", articleVO);

        // 3.融合动态数据和ftl，生成html
        File tempDic = new File(articlePath);
        if (!tempDic.exists()) {
            tempDic.mkdirs();
        }
        String path = articlePath + File.separator + articleVO.getId() + ".html";
        // 输出
        Writer out = new FileWriter(path);
        template.process(map, out);
        out.close();
    }

    /**
     * 文章生成HTML存储到GridFS中
     *
     * @param articleId
     * @return
     * @throws Exception
     */
    public String createArticleHTMLToGridFS(String articleId) throws Exception {
		
        // 0.配置freemarker基本环境
        Configuration cfg = new Configuration(Configuration.getVersion());
        // 声明freemarker模板所需加载的目录的位置
        String classpath = this.getClass().getResource("/").getPath();
        cfg.setDirectoryForTemplateLoading(new File(classpath + "templates"));

        // 1.获得现有的模板ftl文件
        Template template = cfg.getTemplate("detail.ftl", "utf-8");

        // 2.获得动态数据
        ArticleDetailVO articleVO = getArticleDetail(articleId);

        Map<String, Object> map = new HashMap<>();
        map.put("articleDetail", articleVO);

        //获取html内容
        String htmlContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);

        InputStream inputStream = IOUtils.toInputStream(htmlContent);

        ObjectId fileId = gridFSBucket.uploadFromStream(articleVO.getId() + ".html", inputStream);

        return fileId.toString();
    }

    /**
     * 发起远程调用，请求文章服务根据articleId获得文章的信息
     *
     * @param articleId
     * @return
     */
    public ArticleDetailVO getArticleDetail(String articleId) {

        String articleServerUrlExecute
                = "http://"
                + MyServiceList.SERVICE_ARTICLE
                + "/portal/article/detail?articleId="
                + articleId;
        ResponseEntity<GraceJSONResult> responseEntity
                = restTemplate.getForEntity(articleServerUrlExecute, GraceJSONResult.class);
        GraceJSONResult bodyResult = responseEntity.getBody();
        ArticleDetailVO articleVO = null;
        if (bodyResult.getStatus() == 200) {
            String detailJson = JsonUtils.objectToJson(bodyResult.getData());
            articleVO = JsonUtils.jsonToPojo(detailJson, ArticleDetailVO.class);
        }
        return articleVO;
    }

}